package cn.venny.doudian.utils;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

public class DateUtil {

    // ==格式到年==
    /**
     * 日期格式，年份，例如：2004，2008
     */
    public static final String DATE_FORMAT_YYYY = "yyyy";


    // ==格式到年月 ==
    /**
     * 日期格式，年份和月份，例如：200707，200808
     */
    public static final String DATE_FORMAT_YYYYMM = "yyyyMM";

    /**
     * 日期格式，年份和月份，例如：200707，2008-08
     */
    public static final String DATE_FORMAT_YYYY_MM = "yyyy-MM";


    // ==格式到年月日==
    /**
     * 日期格式，年月日，例如：050630，080808
     */
    public static final String DATE_FORMAT_YYMMDD = "yyMMdd";

    /**
     * 日期格式，年月日，用横杠分开，例如：06-12-25，08-08-08
     */
    public static final String DATE_FORMAT_YY_MM_DD = "yy-MM-dd";

    /**
     * 日期格式，年月日，例如：20050630，20080808
     */
    public static final String DATE_FORMAT_YYYYMMDD = "yyyyMMdd";

    /**
     * 日期格式，年月日，用横杠分开，例如：2006-12-25，2008-08-08
     */
    public static final String DATE_FORMAT_YYYY_MM_DD = "yyyy-MM-dd";

    /**
     * 日期格式，年月日，例如：2016.10.05
     */
    public static final String DATE_FORMAT_POINTYYYYMMDD = "yyyy.MM.dd";

    /**
     * 日期格式，年月日，例如：2016年10月05日
     */
    public static final String DATE_TIME_FORMAT_YYYY年MM月DD日 = "yyyy年MM月dd日";


    // ==格式到年月日 时分 ==

    /**
     * 日期格式，年月日时分，例如：200506301210，200808081210
     */
    public static final String DATE_FORMAT_YYYYMMDDHHmm = "yyyyMMddHHmm";

    /**
     * 日期格式，年月日时分，例如：20001230 12:00，20080808 20:08
     */
    public static final String DATE_TIME_FORMAT_YYYYMMDD_HH_MI = "yyyyMMdd HH:mm";

    /**
     * 日期格式，年月日时分，例如：2000-12-30 12:00，2008-08-08 20:08
     */
    public static final String DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI = "yyyy-MM-dd HH:mm";


    // ==格式到年月日 时分秒==
    /**
     * 日期格式，年月日时分秒，例如：20001230120000，20080808200808
     */
    public static final String DATE_TIME_FORMAT_YYYYMMDDHHMISS = "yyyyMMddHHmmss";

    /**
     * 日期格式，年月日时分秒，年月日用横杠分开，时分秒用冒号分开
     * 例如：2005-05-10 23：20：00，2008-08-08 20:08:08
     */
    public static final String DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS = "yyyy-MM-dd HH:mm:ss";

    /**
     * 日期格式，年月日时分秒，年月日用横杠分开，时分秒用冒号分开
     * 例如：2008/08/08 20:08:08
     */
    public static final String YYYY_MM_DD_HH_MI_SS_SLASH = "yyyy-MM-dd HH:mm:ss";

    // ==格式到年月日 时分秒 毫秒==
    /**
     * 日期格式，年月日时分秒毫秒，例如：20001230120000123，20080808200808456
     */
    public static final String DATE_TIME_FORMAT_YYYYMMDDHHMISSSSS = "yyyyMMddHHmmssSSS";


    // ==特殊格式==
    /**
     * 日期格式，月日时分，例如：10-05 12:00
     */
    public static final String DATE_FORMAT_MMDDHHMI = "MM-dd HH:mm";

    /**
     * 订单查询时间分割
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public static List<Map<String, Object>> splitOrderRequestTime(LocalDateTime startTime, LocalDateTime endTime) {
        return splitOrderRequestTime(startTime, endTime, 1, ChronoUnit.DAYS);
    }

    /**
     * 订单查询时间分割(小时)
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public static List<Map<String, Object>> splitOrderRequestTimeHours(LocalDateTime startTime, LocalDateTime endTime) {
        return splitOrderRequestTime(startTime, endTime, 1, ChronoUnit.HOURS);
    }


    /**
     * 订单查询时间分割
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public static List<Map<String, Object>> splitOrderRequestTime(LocalDateTime startTime, LocalDateTime endTime, long amountToSubtract, TemporalUnit unit) {
        List<Map<String, Object>> mapList = new CopyOnWriteArrayList<>();
        while (endTime.isAfter(startTime)) {
            LocalDateTime time1 = endTime;
            endTime = endTime.minus(amountToSubtract, unit);
            LocalDateTime time2;
            if (endTime.isAfter(startTime)) {
                time2 = endTime;
            } else {
                time2 = startTime;
            }
            Map<String, Object> m = new HashMap<>();
            m.put("start_confirm_at", time2.toEpochSecond(ZoneOffset.ofHours(8)));
            m.put("end_confirm_at", time1.toEpochSecond(ZoneOffset.ofHours(8)));
            m.put("startTime", time2);
            m.put("endTime", time1);
            mapList.add(m);
        }
        return mapList;
    }

    /**
     * 时间戳毫秒值->localDateTime，仅使用于中国，（国际则需要修改）
     * @param milliseconds 时间戳毫秒值
     * @return localDateTime
     */
    public static LocalDateTime millisecondsToLocalDateTime(long milliseconds) {
        return Instant.ofEpochMilli(milliseconds).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
    }

    /**
     * localDateTime format
     * @param dateTime the local date time
     * @return the format date time
     */
    public static String localDateTimeFormat(LocalDateTime dateTime) {
        return dateTime.format(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS));
    }

    /**
     * localDateTime format
     * @param dateTime the local date time
     * @param format   the format eg: 'yyyy-MM-dd HH:mm:ss'
     * @return the format date time
     */
    public static String localDateTimeFormat(LocalDateTime dateTime, String format) {
        if (!StringUtils.hasText(format)) {
            format = DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS;
        }
        return dateTime.format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * 时间戳毫秒值转指定格式时间字符串
     * @param milliseconds 时间戳毫秒值
     * @param format       the format eg: 'yyyy-MM-dd HH:mm:ss'
     * @return the format date time
     */
    public static String millisecondsToString(long milliseconds, String format) {
        return localDateTimeFormat(millisecondsToLocalDateTime(milliseconds), format);
    }

    /**
     * 时间戳毫秒值转指定格式时间字符串
     * @param milliseconds 时间戳毫秒值
     * @return the format date time
     */
    public static String millisecondsToString(long milliseconds) {
        return millisecondsToString(milliseconds, null);
    }

    /**
     * 字符串转LocalDateTime
     * @param dateStr 日期字符串
     * @param format  字符串格式
     * @return LocalDateTime
     */
    public static LocalDateTime strToLocalDateTime(String dateStr, String format) {
        if (!StringUtils.hasText(format)) {
            format = DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS;
        }
        return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(format));
    }

    /**
     * local date time 转 时间戳毫秒值
     * @param dateTime the local date time
     * @return 时间戳毫秒值
     */
    public static long localDateTimeToMilliseconds(LocalDateTime dateTime) {
        return dateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
    }

    /**
     * 字符串转时间戳毫秒值
     * @param dateStr 时间字符串
     * @param patten  指定时间格式
     * @return 时间戳毫秒值
     */
    public static long strToMilliseconds(String dateStr, String patten) {
        if (!StringUtils.hasText(patten)) {
            patten = DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS;
        }
        return localDateTimeToMilliseconds(strToLocalDateTime(dateStr, patten));
    }

    /**
     * 字符串转时间戳毫秒值
     * @param dateStr 时间字符串
     * @return 时间戳毫秒值
     */
    public static long strToMilliseconds(String dateStr) {
        return strToMilliseconds(dateStr, null);
    }


    public static String format(LocalDateTime time, String pattern) {
        if (!StringUtils.hasText(pattern)) {
            pattern = DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS;
        }
        return time.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static String formatStr(Long timestamp, String pattern) {
        if (!StringUtils.hasText(pattern)) {
            pattern = DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS;
        }
        final LocalDateTime dateTime = LocalDateTime.ofInstant(new Date(timestamp).toInstant(), ZoneId.systemDefault());
        return dateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static LocalDateTime format(Long timestamp, String pattern) {
        if (!StringUtils.hasText(pattern)) {
            pattern = DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS;
        }
        return LocalDateTime.ofInstant(new Date(timestamp).toInstant(), ZoneId.systemDefault());
    }

    public static LocalDateTime parseTimestampToLocalDateTime(Long secondTimestamp) {
        return Instant.ofEpochMilli(secondTimestamp).atZone(ZoneOffset.systemDefault()).toLocalDateTime();
    }

}
